﻿#include "VAOneXMLAdaptorSeaFaces.h"
#include "rapidxml.hpp"
#include <QFile>
#include <iostream>
#include <QDebug>
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsPhysics.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbsNCT.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEAFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEAFlatCurvedFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsTriangles.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractElement.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementFactory.h"

namespace IO
{
    bool VAOneXMLAdaptorSeaFaces::adaptR()
    {
        bool b = true;

        //数据检查
        if(nullptr == _node)
        {
            return false;
        }

        Acoustics::FITKSEAFaceManager *dataManager = dynamic_cast<Acoustics::FITKSEAFaceManager*>(_dataObj);
        if(nullptr == dataManager)
        {
            return false;
        }

        if (Acoustics::FITKAbstractSEASubSys::SEASSNone == getNodeType())
        {
            return true;
        }

        rapidxml::xml_node<char>* child =  _node->first_node(getNodeName().toStdString().c_str());
        while(nullptr != child)// 判断节点是否存在
        {
            //根据类型创建对象
            Acoustics::FITKAbstractSEAFace *data = createDataObjNode();
            if (nullptr != data)
            {
                //<SinglyCurvedFace corner_index1="2" corner_index2="6" corner_index3="8" face_id="3">
                readCell(child, data);

                dataManager->appendDataObj(data);

                child = child->next_sibling(getNodeName().toStdString().c_str());
            }
        }

        // 返回操作是否成功
        return b;
    }

    bool VAOneXMLAdaptorSeaFaces::adaptW()
    {
        Acoustics::FITKSEAFaceManager *dataManager = dynamic_cast<Acoustics::FITKSEAFaceManager*>(_dataObj);
        if ((nullptr == dataManager) || (nullptr == _node)) return false;

        if (Acoustics::FITKAbstractSEASubSys::SEASSNone == getNodeType()) return true;

        const int n = dataManager->getDataCount();
        for (int i = 0; i < n; ++i)
        {
            Acoustics::FITKAbstractSEAFace* data = dynamic_cast<Acoustics::FITKAbstractSEAFace*>(dataManager->getDataByIndex(i));
            if (nullptr == data) continue;

            //类型过滤
            if (getNodeType() != data->getFaceType()) continue;

            //创建节点
            rapidxml::xml_node<char>* node = createNodeElement(_node, getNodeName());
            if (nullptr == node)
            {
                qDebug()<<"Write Face node create failed";
                return false;
            }

            //单个face写入
            writeCell(data, node);
        }

        // 返回操作是否成功
        return true;
    }

    void VAOneXMLAdaptorSeaFaces::readFaceId(rapidxml::xml_node<char> *node, Acoustics::FITKAbstractSEAFace *data)
    {
        if ((nullptr == node) || (nullptr == data)) return;

        // <FlatPlateFace face_id="1">
        //         <NodeRef nodeid="13"/>
        //         <NodeRef nodeid="14"/>
        //         <Triangle node_id1="13" node_id2="154" node_id3="59"/>
        //         <Triangle node_id1="13" node_id2="154" node_id3="59"/>
        //         <PositiveFace trim_ref="Multiple NCT" trim_coverage="0.99"/>
        //         <NegativeFace trim_ref="2-layer treatment" trim_coverage="0.88"/>
        //</FlatPlateFace>

        // <SinglyCurvedFace face_id="7" face_name="" corner_index1="14" corner_index2="67" corner_index3="81">
        //         <NodeRef nodeid="13"/>
        //         <NodeRef nodeid="14"/>
        //         <Triangle node_id1="13" node_id2="154" node_id3="59"/>
        //         <Triangle node_id1="13" node_id2="154" node_id3="59"/>
        //         <PositiveFace trim_ref="Multiple NCT" trim_coverage="0.99"/>
        //         <NegativeFace trim_ref="2-layer treatment" trim_coverage="0.88"/>
        //</SinglyCurvedFace>

        // <DoublyCurvedShellFace face_id="15" face_name="" number_of_rings="1" tip_nodeid="16920" nodes_per_ring="198">
        //         <NodeRef nodeid="13"/>
        //         <NodeRef nodeid="14"/>
        //         <Triangle node_id1="13" node_id2="154" node_id3="59"/>
        //         <Triangle node_id1="13" node_id2="154" node_id3="59"/>
        //         <PositiveFace trim_ref="Multiple NCT" trim_coverage="0.99"/>
        //         <NegativeFace trim_ref="2-layer treatment" trim_coverage="0.88"/>
        //</DoublyCurvedShellFace>

        bool bOk = true;
        int faceId = readIntAttribute(node, "face_id", &bOk);
        if (true != bOk)
        {
            qDebug()<<"face id read error";
            return;
        }

        data->setUserData(Core::FITKUserRole, faceId); //通过user data 存贮face id  板数据读取时根据faceid 转换成objid存储在板数据结构里
    }

    QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> VAOneXMLAdaptorSeaFaces::readNode(rapidxml::xml_node<char> *node)
    {
        if  (nullptr == node)
        {
            return QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode>();
        }

        bool bOk = true;
        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> listNode;
        Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNodeType type = Acoustics::FITKAbstractSEASubSysWithNodes::Path;

        rapidxml::xml_node<char>* child = node->first_node("NodeRef");
        while (nullptr != child)
        {
            int nodeid = readIntAttribute(child, "nodeid", &bOk);
            if (true != bOk)
            {
                qDebug()<<"Face Node id read error";
                return listNode;
            }

            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode dataNode;
            dataNode._id = nodeid;
            dataNode._type = type;

            listNode<<dataNode;

            child = child->next_sibling("NodeRef");
        }

        return listNode;
    }

    void VAOneXMLAdaptorSeaFaces::readTriangle(rapidxml::xml_node<char> *node, Acoustics::FITKAbstractSEAFace *data)
    {
        if ((nullptr == data) || (nullptr == node))
        {
            return;
        }

        bool bOk = true;

        Acoustics::FITKAcousticsTriangles* tri = data->getTriangleMesh();
        if (nullptr == tri)
        {
            qDebug()<<"Acoustics Triangles null";
            return;
        }

        //读取三角单元信息
        rapidxml::xml_node<char>* child = node->first_node("Triangle");
        while (nullptr != child)
        {
            int value1 = readIntAttribute(child, "node_id1", &bOk);
            if (true != bOk)
            {
                qDebug()<<"Face tri node_id1 id read error";
                return;
            }

            int value2 = readIntAttribute(child, "node_id2", &bOk);
            if (true != bOk)
            {
                qDebug()<<"Face tri node_id2 id read error";
                return;
            }

            int value3 = readIntAttribute(child, "node_id3", &bOk);
            if (true != bOk)
            {
                qDebug()<<"Face tri node_id3 id read error";
                return;
            }

            Interface::FITKAbstractElement* element = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
            element->setNodeID(QList<int>() <<value1<<value2<<value3);
            tri->appendElement(element);

            child = child->next_sibling("Triangle");
        }
    }

    void VAOneXMLAdaptorSeaFaces::readNCT(rapidxml::xml_node<char> *node, Acoustics::FITKAbstractSEAFace *data)
    {
        if ((nullptr == data) || (nullptr == node))
        {
            return;
        }

        bool bOk = true;

        //噪声信息
        rapidxml::xml_node<char> * child = node->first_node("PositiveFace");
        if (nullptr == child)
        {
            qDebug()<<"nct out node read error";
            return;
        }

        QString name = readStrAttribute(child, "trim_ref", &bOk);
        if (true != name.isEmpty())
        {
            int id = getNCTID(name);
            data->setOutsideNCTID(id);
        }
        double value = readDoubleAttribute(child, "trim_coverage", &bOk);
        if (true == bOk)  //属性存在时保存数据
        {
            data->setOutsideNCTCoveredArea(value * 100);
        }

        child = node->first_node("NegativeFace");
        if (nullptr == child)
        {
            qDebug()<<"nct in node read error";
            return;
        }
        name = readStrAttribute(child, "trim_ref", &bOk);
        if (true != name.isEmpty())
        {
            int id = getNCTID(name);
            data->setInsideNCTID(id);
        }
        value = readDoubleAttribute(child, "trim_coverage", &bOk); //属性存在时保存数据
        if (true == bOk)
        {
            data->setInsideNCTCoveredArea(value * 100);
            return;
        }
    }

    void VAOneXMLAdaptorSeaFaces::readCell(rapidxml::xml_node<char> *node, Acoustics::FITKAbstractSEAFace *data)
    {
        if ((nullptr == data) || (nullptr == node)) return;

        readFaceId(node, data);

        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> listNode = readNode(node);

        //起始节点类型设置
        if (2 <= listNode.size())
        {
            listNode.first()._type = Acoustics::FITKAbstractSEASubSysWithNodes::Start;
            listNode.last()._type = Acoustics::FITKAbstractSEASubSysWithNodes::Finish;
        }

        data->setNodes(listNode);

        readTriangle(node, data);

        readNCT(node, data);
    }

    void VAOneXMLAdaptorSeaFaces::writeFaceId(Acoustics::FITKAbstractSEAFace *data, rapidxml::xml_node<char> *node)
    {
        if ((nullptr == data) || (nullptr == node))
        {
            return;
        }

        //使用objid作为face id
        int faceId = data->getDataObjectID();
        writeAttribute(node, "face_id", faceId);
    }

    void VAOneXMLAdaptorSeaFaces::writeNode(Acoustics::FITKAbstractSEAFace *data, rapidxml::xml_node<char> *node)
    {
        if ((nullptr == data) || (nullptr == node))
        {
            return;
        }

        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> listNode = data->getNodes();

        //写入点数据
        for (auto key : listNode)
        {
            rapidxml::xml_node<char>* child = createNodeElement(node, "NodeRef");
            if (nullptr == child)
            {
                qDebug()<<"Face Node write failed";
                return;
            }

            writeAttribute(child, "nodeid", key._id);
        }
    }

    void VAOneXMLAdaptorSeaFaces::writeTriangle(Acoustics::FITKAbstractSEAFace *data, rapidxml::xml_node<char> *node)
    {
        if ((nullptr == data) || (nullptr == node)) return;

        //写入三角单元
        Acoustics::FITKAcousticsTriangles* tri = data->getTriangleMesh();
        if (nullptr == tri)
        {
            qDebug()<<"Acoustics Triangles null";
            return;
        }

        int count = tri->getElementCount();
        for (int i = 0; i < count; i++)
        {
            Interface::FITKAbstractElement* ele = tri->getElementAt(i);
            rapidxml::xml_node<char>* child = createNodeElement(node, "Triangle");
            if ((nullptr == child) || (nullptr == ele))
            {
                qDebug()<<"Face Tri write failed";
                return;
            }

            int nNodes = ele->getNodeCount();
            if (nNodes != 3)   continue;

            writeAttribute(child, "node_id1", ele->getNodeID(0));
            writeAttribute(child, "node_id2", ele->getNodeID(1));
            writeAttribute(child, "node_id3", ele->getNodeID(2));
        }
    }

    void VAOneXMLAdaptorSeaFaces::writeNCT(Acoustics::FITKAbstractSEAFace *data, rapidxml::xml_node<char> *node)
    {
        if ((nullptr == data) || (nullptr == node)) return;

        //噪声信息
        rapidxml::xml_node<char>* child = createNodeElement(node, "PositiveFace");
        if (nullptr == child)
        {
            qDebug()<<"write nct create node error";
            return;
        }
        QString name = getNCTName(data->getOutsideNCTID());
        if (true != name.isEmpty())
        {
            writeAttribute(child, "trim_ref", name);
        }
        writeAttribute(child, "trim_coverage", data->getOutsideNCTCoveredArea() / 100);

        child = createNodeElement(node, "NegativeFace");
        if (nullptr == child)
        {
            qDebug()<<"write nct create node error";
            return;
        }
        name = name = getNCTName(data->getInsideNCTID());
        if (true != name.isEmpty())
        {
            writeAttribute(child, "trim_ref", name);
        }
        writeAttribute(child, "trim_coverage", data->getInsideNCTCoveredArea() / 100);
    }

    void VAOneXMLAdaptorSeaFaces::writeCell(Acoustics::FITKAbstractSEAFace *data, rapidxml::xml_node<char> *node)
    {
        if ((nullptr == data) || (nullptr == node)) return;

        writeFaceId(data, node);

        writeNode(data, node);

        writeTriangle(data, node);

        writeNCT(data, node);
    }
}
